// logger/logger.go
package logger

import (
	"os"
	"path/filepath"
	"time"

	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"gopkg.in/natefinch/lumberjack.v2"
)

var Logger *zap.Logger
var Sugar *zap.SugaredLogger

// InitLogger initializes the global logger instance
func InitLogger(env string) error {
	var err error
	if env == "prod" {
		Logger, err = newProductionLogger()
	} else {
		Logger, err = newDevelopmentLogger()
	}

	if err != nil {
		return err
	}
	Sugar = Logger.Sugar()

	// Replace global logger
	zap.ReplaceGlobals(Logger)
	return nil
}

func newProductionLogger() (*zap.Logger, error) {
	// 1. 获取日志文件路径（可执行文件相对路径下的 log/YYYY-MM-DD.log）
	logPath, err := getProductionLogPath()
	if err != nil {
		return nil, err
	}

	// 2. 配置日志切割（lumberjack 处理文件轮转）
	lumberjackWriter := &lumberjack.Logger{
		Filename:   logPath, // 日志文件路径
		MaxSize:    100,     // 单个文件最大 100MB
		MaxBackups: 7,       // 保留最近 7 个备份文件
		MaxAge:     7,       // 日志文件保留 7 天
		Compress:   true,    // 压缩旧日志文件
	}

	// 3. 配置 Zap 编码器（JSON 格式，生产环境推荐）
	encoderConfig := zapcore.EncoderConfig{
		TimeKey:       "time",
		LevelKey:      "level",
		MessageKey:    "msg",
		CallerKey:     "caller",
		StacktraceKey: "stacktrace",
		EncodeLevel:   zapcore.LowercaseLevelEncoder, // 级别小写（info/warn/error）
		EncodeTime:    zapcore.ISO8601TimeEncoder,    // 时间格式：ISO8601（如 2025-11-08T12:34:56+08:00）
		EncodeCaller:  zapcore.ShortCallerEncoder,    // 调用者路径简写（如 logger/logger.go:45）
		LineEnding:    zapcore.DefaultLineEnding,
	}

	// 4. 构建 Zap 核心组件
	core := zapcore.NewCore(
		zapcore.NewJSONEncoder(encoderConfig), // JSON 格式输出
		zapcore.AddSync(lumberjackWriter),     // 输出到 lumberjack 管理的文件
		zap.NewAtomicLevelAt(zap.InfoLevel),   // 生产环境默认只输出 Info 及以上级别
	)

	// 5. 构建 Logger（添加调用者信息和错误级别的堆栈跟踪）
	logger := zap.New(core, zap.AddCaller(), zap.AddStacktrace(zap.ErrorLevel))
	return logger, nil
}

// getProductionLogPath 生成生产环境日志路径（可执行文件相对路径/log/YYYY-MM-DD.log）
func getProductionLogPath() (string, error) {
	// 获取可执行文件的绝对路径
	exePath, err := os.Executable()
	if err != nil {
		return "", err
	}

	// 解析可执行文件所在目录（处理符号链接）
	exeDir, err := filepath.EvalSymlinks(filepath.Dir(exePath))
	if err != nil {
		return "", err
	}

	// 构造 log 目录路径（可执行文件目录 + log 子目录）
	logDir := filepath.Join(exeDir, "log")
	// 创建 log 目录（若不存在，递归创建）
	if err := os.MkdirAll(logDir, 0755); err != nil { // 0755 权限：所有者读写执行，其他读执行
		return "", err
	}

	// 生成按日期命名的日志文件名（如 2025-11-08.log）
	dateStr := time.Now().Format("2006-01-02")
	logFileName := dateStr + ".log"

	// 拼接完整日志文件路径
	return filepath.Join(logDir, logFileName), nil
}

func newDevelopmentLogger() (*zap.Logger, error) {
	// Development config already has colorized output
	config := zap.NewDevelopmentConfig()
	config.EncoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder
	return config.Build()
}

// GetLogger returns the global logger instance
func GetLogger() *zap.Logger {
	return Logger
}

func GetSugar() *zap.SugaredLogger {
	return Sugar
}

// NewZapLoggerWriter creates a writer that bridges to zap logger
func NewZapLoggerWriter(logger *zap.SugaredLogger) *ZapLoggerWriter {
	return &ZapLoggerWriter{logger: logger}
}

// ZapLoggerWriter is a custom writer to bridge Gin's log output to zap
type ZapLoggerWriter struct {
	logger *zap.SugaredLogger
}

func (w *ZapLoggerWriter) Write(p []byte) (n int, err error) {
	w.logger.Info(string(p)) // 将接收到的字节数据作为info级别日志记录
	return len(p), nil
}
